package com.ltmall.api.weixin.pay.utils;

import com.ltmall.api.weixin.pay.Constants;
import com.ltmall.api.weixin.pay.model.ScanPayQueryReqData;
import com.ltmall.api.weixin.pay.model.UnifiedorderPayReqDate;
import com.ltmall.api.weixin.tecent.comm.MD5;
import com.ltmall.api.weixin.tecent.comm.RandomStringGenerator;
import com.ltmall.api.weixin.tecent.comm.XMLParser;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;

import java.util.*;

public class WeixinUtils {

    public enum WXPayType {
        OAPay, AppPay
    }

    public static String getOut_trade_no() {
        String out_trade_no = String.format("NO%s%s", DateUtil.formatDate(new Date(), DateUtil.LOCATE_DATE_FORMAT),
                getRandomNumber(10));
        return out_trade_no;
    }

    public static String getMchBillno() {
        String mchBillno = String.format("%s%s%s", Constants.OA_MCH_ID, DateUtil.formatDate(new Date(), "yyyyMMdd"), getRandomNumber(10));
        return mchBillno;
    }

    public static String getRandomNumber(int n) {
        if (n <= 0)
            return null;
        String str = "";
        for (int i = 0; i < n; i++) {
            str += (int) (Math.random() * 10);
        }
        return str;
    }

    /**
     * 统一下单
     *
     * @param name      商品名称
     * @param total_fee 价格（单位：分）
     * @param ip        ip
     */
    public static Map<String, String> payUnifiedorder(WXPayType payType, String body, int total_fee, String ip,
                                                      String out_trade_no, String notify_url, String open_id) {

        UnifiedorderPayReqDate unifiedorderPayReqDate = null;

        if (payType == WXPayType.AppPay) {
            unifiedorderPayReqDate = new UnifiedorderPayReqDate(Constants.APP_ID, Constants.MCH_ID, "", body, "", "",
                    out_trade_no, "", total_fee, ip, "", "", "", notify_url, "APP", "", "");
        } else {
            unifiedorderPayReqDate = new UnifiedorderPayReqDate(Constants.OA_APP_ID, Constants.OA_MCH_ID, "", body, "",
                    "", out_trade_no, "", total_fee, ip, "", "", "", notify_url, "JSAPI", "", open_id);
        }

        String postDataXML = unifiedorderPayReqDate.toXml();
        postDataXML = "\n" + postDataXML;
        System.out.println(postDataXML);

        try {
            String res = HttpUtils.postXml(Constants.PAY_UNFIFIEDORDER, postDataXML);
            System.out.println(res);
            Map<String, String> map = XMLParser.getMapFromXML(res);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public static Map<String, String> payOrderquery(WXPayType payType, String out_trade_no) {
        ScanPayQueryReqData scanPayQueryReqData = null;
        if (payType == WXPayType.AppPay) {
            scanPayQueryReqData = new ScanPayQueryReqData(Constants.APP_ID, Constants.MCH_ID, null, out_trade_no);
        } else {
            scanPayQueryReqData = new ScanPayQueryReqData(Constants.OA_APP_ID, Constants.OA_MCH_ID, null, out_trade_no);
        }

        String postDataXML = scanPayQueryReqData.toXml();
        postDataXML = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + postDataXML;
        System.out.println(postDataXML);
        try {
            String res = HttpUtils.postXml(Constants.PAY_QUERY_API, postDataXML);
            System.out.println(res);
            Map<String, String> map = XMLParser.getMapFromXML(res);
            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public static String genSign(List<NameValuePair> params) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < params.size(); i++) {
            sb.append(params.get(i).getName());
            sb.append('=');
            sb.append(params.get(i).getValue());
            sb.append('&');
        }
        sb.append("key=");
        sb.append(Constants.KEY);
        String result = MD5.MD5Encode(sb.toString()).toUpperCase();
        return result;
    }

    public static Map<String, String> createAppPay(int totalPrice, String out_trade_no, String body, String ip
            , String notifyUrl, String openid) {

        Map<String, String> map = WeixinUtils.payUnifiedorder(WXPayType.OAPay, body, totalPrice, ip, out_trade_no,
                notifyUrl, openid);
        TreeMap<String, String> outParams = new TreeMap<String, String>();
        if (null != map) {
            String app_id = map.get("appid");
            /*
             * 获取预支付id
             */
            String prepayid = map.get("prepay_id");
            /**
             * 创建预支付sign签名
             */
            String noceStr = RandomStringGenerator.getRandomStringByLength(32);
            String timeStamp = String.valueOf((System.currentTimeMillis() / 1000));

            List<NameValuePair> signParams = new LinkedList<NameValuePair>();
            signParams.add(new BasicNameValuePair("appId", app_id));
            signParams.add(new BasicNameValuePair("nonceStr", noceStr));
            signParams.add(new BasicNameValuePair("package", "prepay_id=" + prepayid));
            signParams.add(new BasicNameValuePair("signType", "MD5"));
            signParams.add(new BasicNameValuePair("timeStamp", timeStamp));
            String sign = WeixinUtils.genSign(signParams);

            /*
             * 返回手机端支付需要的全部参数
             */
            outParams.put("retcode", "0");
            outParams.put("retmsg", "OK");
            outParams.put("appid", app_id);
            outParams.put("noncestr", noceStr);
            outParams.put("partnerid", Constants.OA_MCH_ID);
            outParams.put("package", "prepay_id=" + prepayid);
            outParams.put("prepayid", prepayid);
            outParams.put("out_trade_no", out_trade_no);
            outParams.put("timestamp", timeStamp);
            outParams.put("sign_type", "MD5");
            outParams.put("sign", sign);
        } else {
            outParams.put("retcode", "-1");
            outParams.put("retmsg", "错误：获取不到Token");
        }

        return outParams;
    }

}
